package holmes

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"
)

type write2server func(msg clientMsg) error
type clientMsg struct {
	logTime int64
	level   LogLevel
	msg     string
}
type internetClient struct {
	name      string   //节点名称
	server    string   //服务器地址
	savePath  string   //服务器文件保存地址
	saveLevel LogLevel //最低保存标准

	pipe_name        map[LogLevel]string   //pipe 文件名
	pipe_fd          map[LogLevel]*os.File //pipe 文件名
	now_write2server write2server          //写入方式
	msg_buffer       chan clientMsg
	closed           bool
	closeOver        bool
}

func (client *internetClient) poll() {
	for {
		select {
		case msg := <-client.msg_buffer:
			err := client.now_write2server(msg)
			if err != nil {
				fmt.Printf("分布式日志客户端写入错误:%s\n", err.Error())
			}
		case <-time.After(time.Second * 5):
			if client.closed {
				fmt.Println("分布式日志客户端退出")
				client.closeOver = true
				return
			}
		}
	}
}
func (client *internetClient) send2server(logTime int64, level LogLevel, msg string) error {
	var a clientMsg
	a.level = level
	a.logTime = logTime
	a.msg = msg
	select {
	case client.msg_buffer <- a:
		// case <-time.After(time.Microsecond * 100):
		//	fmt.Printf("%s节点发送超时", client.name)
	}
	return nil
}
func (client *internetClient) send2serverFromHttp(msg clientMsg) error {
	url := fmt.Sprintf("http://%s/v1.0/nodes/%s/%s/%d", client.server, client.name, tagName[msg.level], msg.logTime)
	bodys := strings.NewReader(msg.msg)
	ret, err := http.Post(url, "application/json", bodys)
	if err != nil {
		fmt.Printf("数据节点写入错误:%s\n", err.Error())
		return err
	} else {
		_, err := ioutil.ReadAll(ret.Body)
		if err != nil {
			fmt.Printf("数据节点写入错误:%s\n", err.Error())
			return err
		} else {
			//fmt.Printf("数据节点写入%s返回%s\n", client.name, string(ret_bytes))
		}
	}
	return nil
	return nil
}
func (client *internetClient) send2serverFromPipe(msg clientMsg) error {
	return nil
}
func (client *internetClient) createNode() error {
	url := fmt.Sprintf("http://%s/v1.0/nodes/%s", client.server, client.name)
	bodys := fmt.Sprintf(`{"节点名称":"%s","最大保存文件数":%d,"保存路径":"%s","保存等级":%d}`, client.name, 1000, client.savePath, client.saveLevel)
	ret, err := put(url, bodys)
	if err != nil {
		fmt.Printf("创建数据节点错误:%s\n", err.Error())
		return err
	} else {
		fmt.Printf("创建数据节点%s返回%s\n", client.name, string(ret))
		if !strings.Contains(string(ret), "ok") {
			return errors.New(string(ret))
		}
	}
	return nil
}
func (client *internetClient) closePoll() {
	client.closed = true
}
func (this *internetClient) over() bool {
	return this.closeOver
}

//name server savePath minSaveLevel
//name info event
//name info error event
//name info warn error event
//name info warn error event fatal
//name debug info warn error event fatal
func NewClient(mode IoWriterMode, configs ...string) *internetClient {
	client := new(internetClient)
	client.msg_buffer = make(chan clientMsg, 100)
	switch mode {
	case IoWriterNetMode:
		client.name = configs[0]
		client.server = configs[1]
		client.savePath = configs[2]
		client.saveLevel = LevelFromString(configs[3])
		client.now_write2server = client.send2serverFromHttp
		//3次重连
		for i := 0; i < 3; i++ {
			err := client.createNode()
			if err != nil {
				if i == 2 {
					return nil
				} else {
					//
					time.Sleep(1 * time.Second)
				}
			} else {
				go client.poll()
				break
			}
		}

		return client
	case IoWriterPipeMode:

	}
	return nil
}
func SetDistributeMode(args ...string) func(Logger) Logger {
	fmt.Printf("开启分布式日志模式\n")
	return func(l Logger) Logger {
		l.internet = NewClient(IoWriterNetMode, args...)
		return l
	}
}
func put(url string, data string) ([]byte, error) {
	//生成client 参数为默认
	client := &http.Client{}
	//提交请求
	reqest, err := http.NewRequest("PUT", url, strings.NewReader(data))

	if err != nil {
		return nil, err
	}
	reqest.Header.Set("Content-Type", "application/json")
	//处理返回结果
	response, err := client.Do(reqest)
	if err != nil {
		return nil, err
	}

	//将结果定位到标准输出 也可以直接打印出来 或者定位到其他地方进行相应的处理
	ret_bytes, err := ioutil.ReadAll(response.Body)
	if response.StatusCode != http.StatusOK {
		return nil, errors.New(fmt.Sprintf("错误返回吗%d", response.StatusCode))
	}
	return ret_bytes, nil
}
